
#include "unp.h"

int main(int argc, char * argv[]) {
	hello("ok");
	printf("tcp server listen on port %d\n", SERV_PORT);
	printf("pid=%d\n", getpid());
	Signal(SIGCHLD, sig_chld);// handle child process exit, avoid zombie


	SA_IN servaddr, cliaddr;
	int listenfd, connfd, sockfd, clilen;
	int clients[FD_SETSIZE];
	int nready, i;
	int maxfdp1, maxi;
	fd_set rset, allset;
	char buf[MAXLINE];
	ssize_t n;

	listenfd = Socket(AF_INET, SOCK_STREAM, 0);

	bzero(&servaddr, sizeof(servaddr));
	servaddr.sin_family = AF_INET;
	servaddr.sin_port = htons(SERV_PORT);
	servaddr.sin_addr.s_addr = htonl(INADDR_ANY);

	Bind(listenfd, (SA*)&servaddr, sizeof(servaddr));
	Listen(listenfd, LISTENQ);


	FD_ZERO(&allset);
	FD_SET(listenfd, &allset);
	maxfdp1 = listenfd;
	maxi = -1;
	for (i = 0; i < FD_SETSIZE; i++) {
		clients[i] = -1;
	}

	clilen = sizeof(cliaddr);

	for (;;) {
		fd_set rset;
		rset = allset;

		nready = select(maxfdp1 + 1, &rset, NULL, NULL, NULL);

		if (FD_ISSET(listenfd, &rset)) { // a new client is connect
			connfd = Accept(listenfd, (SA*)&cliaddr, &clilen);
			inet_ntop(AF_INET, &cliaddr.sin_addr, buf, sizeof(buf));
			printf("got new client, fd=%d, ip=%s, port=%d\n", connfd, buf , ntohs(cliaddr.sin_port));
			for (i = 0; i < FD_SETSIZE; i++) {
				if (clients[i] < 0) {
					clients[i] = connfd;
					break;
				}
			}
			if (i == FD_SETSIZE) {
				err_quit("two many clients");
			}
			maxfdp1 = max(maxfdp1, connfd);
			FD_SET(connfd, &allset);
			maxi = max(maxi, i);

			if (--nready <= 0 )continue;
		}

		for (i = 0; i <= maxi; i++) {
			if ((sockfd = clients[i]) < 0 )continue;

			if (FD_ISSET(clients[i], &rset)) {
				// str_echo(clients[i]);
				if ((n = readline(sockfd, buf, MAXLINE)) > 0) {
					printf("to fd=%d,%s", sockfd, buf);
					Write(sockfd, buf, n);
				} else if (n == 0) {
					printf("client end, fd=%d\n", sockfd);
					FD_CLR(sockfd, &allset);
					clients[i] = -1;
					shutdown(sockfd, SHUT_RDWR);
				}
			}
		}
	}
	return 0;
}
